﻿import java.util.Map;
import java.util.HashMap;
import java.util.Random;
import java.util.Set;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Hashtable;
import java.util.TreeMap;

public class JavaHashMap2 {
	public static void main(String[] args) {
		HashMap h2 = new HashMap();
		for (int i = 0; i < 10; i++)
			h2.put(new Element(i), new Figureout());
		System.out.println("h2:");
		System.out.println("Get the result for Element:");
		Element test = new Element(5);
		if (h2.containsKey(test))
			System.out.println((Figureout) h2.get(test));
		else
			System.out.println("Not found");
	}
}

/*
 * 在这个例子中，Element用来索引对象Figureout,也即Element为key，Figureout为value。在Figureout中随机生成一个浮点数
 * ，如果它比0.5大，打印"OK!"，否则打印"Impossible!"。之后查看Element(5)对应的Figureout结果如何。
 * 结果却发现，无论你运行多少次，得到的结果都是"Not found"。也就是说索引Element(5)并不在HashMap中。这怎么可能呢？
 * 原因得慢慢来说：Element的HashCode方法继承自Object，而Object中的HashCode方法返回的HashCode对应于当前的地址，
 * 也就是说对于不同的对象，即使它们的内容完全相同，用HashCode（）返回的值也会不同。这样实际上违背了我们的意图。因为我们在使用HashMap时，
 * 希望利用相同内容的对象索引得到相同的目标对象，这就需要HashCode()在此时能够返回相同的值。在上面的例子中，我们期望new Element(i)
 * (i=5)与 Element test=new Element(5)是相同的，而实际上这是两个不同的对象，尽管它们的内容相同，但它们在内存中的地址不同。
 */
class Element {
	int number;

	public Element(int n) {
		number = n;
	}
}

// class Element{
// int number;
// public Element(int n){
// number=n;
// }
// public int hashCode(){
// return number;
// }
// public boolean equals(Object o){
// return (o instanceof Element) && (number==((Element)o).number);
// }
// }
// 在这里Element覆盖了Object中的hashCode()和equals()方法。覆盖hashCode()使其以number的值作为hashcode返回，这样对于相同内容的对象来说它们的hashcode也就相同了。而覆盖equals()是为了在HashMap判断两个key是否相等时使结果有意义（有关重写equals()的内容可以参考我的另一篇文章《重新编写Object类中的方法
// 》）。修改后的程序运行结果如下：
// h2:
// Get the result for Element:
// Impossible!
//
// 请记住：如果你想有效的使用HashMap，你就必须重写在其的HashCode()。还有两条重写HashCode()的原则：
//
// 不必对每个不同的对象都产生一个唯一的hashcode，只要你的HashCode方法使get()能够得到put()放进去的内容就可以了。即"不为一原则"。
// 生成hashcode的算法尽量使hashcode的值分散一些，不要很多hashcode都集中在一个范围内，这样有利于提高HashMap的性能。即"分散原则"。
//
class Figureout {
	Random r = new Random();
	boolean possible = r.nextDouble() > 0.5;

	public String toString() {
		if (possible)
			return "OK!";
		else
			return "Impossible!";
	}
}